package logic

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"log"
	"strconv"
	"time"
	"yundian/internel/app/dao"
	"yundian/internel/app/dao/memberdao"
	"yundian/internel/app/helper/request"
	"yundian/internel/app/models/devices"
	"yundian/internel/app/models/membermodel"
	"yundian/internel/app/models/orders"
	"yundian/internel/app/models/paysetting"
	"yundian/internel/app/models/placemodel"
	"yundian/internel/app/models/ploys"
	"yundian/internel/app/models/prices"
	"yundian/internel/app/models/users"
	"yundian/internel/pkg/dingo"
	"yundian/internel/pkg/dingo/global"
	"yundian/internel/pkg/utils"
	"yundian/internel/pkg/wechatpay"
)

type WxOrderLogic struct {
	TradeNo   string
	PayClient *wechatpay.PayClient
	WxConfig  *paysetting.PaySetting
}

func NewWxOrderLogic() *WxOrderLogic {
	tradeNo := utils.Join(global.Const.Pre.OrderPre, time.Now().Format("20060102150405"), utils.GetRandomInt(6))
	payClient := wechatpay.NewPayClient(nil)
	wxConfig := NewSettingLogic().GetPaySetting()
	return &WxOrderLogic{TradeNo: tradeNo, PayClient: payClient, WxConfig: wxConfig}
}

// 微信支付分订单创建
func (wxlogic *WxOrderLogic) ServiceOrderCreate(param *request.CreateOrderReq) (*wechatpay.PayData, error) {
	priceInfo := dao.NewPricesDao().GetPriceDetail(param.ProductId).Unwrap().(*prices.PriceModel) // 获取价格信息
	placeInfo := dao.NewPlaceDao().GetPlaceById(priceInfo.PlaceId).Unwrap().(*placemodel.PlaceModel)  // 获取商户信息
	var money, useTime int64                                                                      // 单位-分
	if param.FeeMode == 1 {                                                                       // 计时
		money = priceInfo.Deposit // 支付押金  // 单套餐
		useTime = int64(priceInfo.MaxTime * 60)
	} else { // 套餐
		money = priceInfo.PayMoney // 支付套餐价
		//money = 1000 // 风险金
		useTime = int64(priceInfo.UseDuration * 60)
	}

	//优惠券

	endtime := wechatpay.FormatIntTime(time.Now().Unix() + useTime) // 服务结束时间 - 当前时间 + 使用时长 (秒)

	apiData := wxlogic.GenServiceOrderApiData(param, money, placeInfo, priceInfo, endtime) // 构建ApiParam
	log.Println("打印测试信息-免押下订单", apiData)
	respData, err := wechatpay.ApiPayScoreOrder(apiData, wxlogic.WxConfig) // 请求微信
	if err != nil {
		return respData, err
	}

	if respData.Get("state") == "CREATED" { // 支付分订单创建成功，生成平台订单
		//dingo.Task(wxlogic.HandleCreateOrderByPayScore, func() { }, param, respData) // 异步
		wxlogic.CreateOrderByPayScore(param, respData, placeInfo) // 同步
		//ok := dao.NewOrderDao().InsertOrderCorrelation(respData.Get("out_order_no")).Unwrap().(bool)
		//if !ok {
		//	log.Println("支付分同步添加订单关联信息失败", respData)
		//}
	}

	resultData := wxlogic.MakeSign(respData) // 二次签名
	var productIdKey = utils.Join("productId-", param.Openid, "-", param.DeviceSn)
	global.Rdb.Set(context.Background(), productIdKey, param.ProductId, time.Hour*24)
	return resultData, nil
}

// 构建API Param
func (wxlogic *WxOrderLogic) GenServiceOrderApiData(param *request.CreateOrderReq, money int64, placeInfo *placemodel.PlaceModel, priceInfo *prices.PriceModel, endTime string) *wechatpay.PayData {

	price := decimal.NewFromInt(priceInfo.PayIntervalPrice).Div(decimal.NewFromInt(100)).StringFixed(0)
	maxPrice := decimal.NewFromInt(priceInfo.MaxPayPrice).Div(decimal.NewFromInt(100)).StringFixed(0)
	hour := decimal.NewFromInt(int64(priceInfo.BaseTimes)).Div(decimal.NewFromInt(60)).IntPart()
	prePrice := decimal.NewFromInt(priceInfo.BasePrice).Div(decimal.NewFromInt(100)).StringFixed(0)

	var description string
	if param.FeeMode == 1 { // 计时
		//description = fmt.Sprintf("%s元/小时，24小时封顶%s元，总封顶%s元", price, maxPrice, maxPrice)
		//description = fmt.Sprintf("0~%d时(%s元/时),%d~24时(%s元/时),总封顶%s元",
		//	hour, prePrice, hour+1, price, maxPrice)
		description = fmt.Sprintf("前%d小时%s元,之后%s元/时,24小时封顶%s元",
			hour, prePrice, price, maxPrice)
	} else { // 套餐
		description = fmt.Sprintf("%d元/%d小时", priceInfo.PayMoney/100, priceInfo.UseDuration/60)
	}

	pd := wechatpay.NewPayData()
	pd.Set("out_order_no", wxlogic.TradeNo)
	pd.Set("appid", wxlogic.WxConfig.AppId)
	pd.Set("service_id", wxlogic.WxConfig.ServerId)
	pd.Set("service_introduction", global.Const.Desc.ServiceIntroduction)
	pd.Set("time_range", &struct {
		StartTime string `json:"start_time"`
		//EndTime   string `json:"end_time"`
	}{
		StartTime: "OnAccept",            
		//EndTime:   endtime,
	})
	pd.Set("location", &struct {
		StartLocation string `json:"start_location"`
	}{
		StartLocation: placeInfo.PlaceName,
	})
	pd.Set("risk_fund", &struct {
		Name        string `json:"name"`
		Amount      int64  `json:"amount"`
		Description string `json:"description"`
	}{
		Name:        "DEPOSIT",
		Amount:      money,
		Description: global.Const.Desc.Description,
	})
	var postPayments []request.PostPayments
	postPayments = append(postPayments, request.PostPayments{
		Name:        global.Const.Desc.PostPaymentsName,
		Amount:      money,
		Description: description,
	})
	pd.Set("post_payments", postPayments)

	pd.Set("notify_url", wxlogic.WxConfig.ScoreNotifyUrl)
	pd.Set("openid", param.Openid)
	pd.Set("attach", param.DeviceSn) // 设备序号

	return pd
}

// MakeSign 二次签名给前端
func (wxlogic *WxOrderLogic) MakeSign(resultData *wechatpay.PayData) *wechatpay.PayData {
	respData := wechatpay.NewPayData()
	respData.Set("mch_id", wxlogic.WxConfig.MchId)
	respData.Set("package", resultData.Get("package"))
	respData.Set("timestamp", wechatpay.TimeStamp())
	respData.Set("nonce_str", wechatpay.RandomStr(32))
	respData.Set("sign_type", wechatpay.SignTypeHMACSHA256)
	paySign := respData.MakeSign(wxlogic.WxConfig.ApiKey, wechatpay.SignTypeHMACSHA256)
	respData.Set("sign", paySign)
	respData.Set("trade_no", resultData.Get("out_order_no"))
	//log.Println("WxPayScoreLogic-MakeSign-打印测试数据sign", paySign)
	return respData
}

// CheckSign 验证签名
func (wxlogic *WxOrderLogic) CheckSign(headers map[string]string, body string) (bool, error) {
	certLogic := NewWxCertLogic()
	wxCert, err := certLogic.LoadCertificate()
	if err != nil {
		return false, err
	}
	certInfo, err := certLogic.DecryptCertificate(wxCert)
	if err != nil {
		return false, err
	}
	//log.Println("打印测试数据 CheckSign", certInfo)
	//log.Println("打印测试数据 serialNo", headers["serial_no"])

	// 验证证书序号
	if certInfo.SerialNo != headers["serial_no"] {
		return false, errors.New("证书号错误或已过期")
	}

	// 构建签名串
	//checkStr := headers["timestamp"] + "\n" + headers["nonce"] + "\n" + body + "\n"

	// 签名验证 - 暂时先放着
	//var keypath = "微信平台证书公钥路径"
	//key, err := ioutil.ReadFile(keypath)
	//
	//blocks, _ := pem.Decode(key)
	//if blocks == nil || blocks.Type != "PUBLIC KEY" {
	//	return false, errors.New("failed to decode PUBLIC KEY")
	//}
	//
	//oldSign, err := base64.StdEncoding.DecodeString(headers["signature"])
	//pub, err := x509.ParsePKIXPublicKey(blocks.Bytes)
	//hashed := sha256.Sum256([]byte(checkStr))
	//err = rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hashed[:], oldSign)
	//
	//return true, err

	return true, nil
}

// 构建完结 API Param
func (wxlogic *WxOrderLogic) OrderCompleteApiData(settMoney int64, priceInfo *prices.PriceModel, placeName string, feeMode uint8, location string, wc *paysetting.PaySetting) string {
	// 创建订单未填写服务结束时间，则完结的时候，服务结束时间必填
	//description := utils.Join("充电时长:",strconv.Itoa(int(useTime)),"秒")
	price := decimal.NewFromInt(priceInfo.PayIntervalPrice).Div(decimal.NewFromInt(100)).StringFixed(0)
	maxPrice := decimal.NewFromInt(priceInfo.MaxPayPrice).Div(decimal.NewFromInt(100)).StringFixed(0)
	hour := decimal.NewFromInt(int64(priceInfo.BaseTimes)).Div(decimal.NewFromInt(60)).IntPart()
	prePrice := decimal.NewFromInt(priceInfo.BasePrice).Div(decimal.NewFromInt(100)).StringFixed(0)

	var description string
	if feeMode == 1 { // 计时
		//description = fmt.Sprintf("%s元/小时，24小时封顶%s元，总封顶%s元", price, maxPrice, maxPrice)
		//description = fmt.Sprintf("0~%d时(%s元/时),%d~24时(%s元/时),总封顶%s元",
		//	hour, prePrice, hour+1, price, maxPrice)
		description = fmt.Sprintf("前%d小时%s元,之后%s元/时,24小时封顶%s元",
			hour, prePrice, price, maxPrice)
	} else { // 套餐
		description = fmt.Sprintf("%d元/%d小时", priceInfo.PayMoney/100, priceInfo.UseDuration/60)
	}

	apiData := &request.PayScoreCompleteReq{
		Appid:     wc.AppId,
		ServiceId: wc.ServerId,
		PostPayments: []request.PostPayments{
			{
				Name:        global.Const.Desc.PostPaymentsName,
				Amount:      settMoney,
				Description: description,
			},
		},
		TimeRange: request.TimeRange{
			EndTime: wechatpay.FormatTime(time.Now()),
		},
		//Location: request.LocationAddress{
		//	EndLocation: placeName,
		//},
		TotalAmount: settMoney,
	}

	if location != "{}" {
		apiData.Location = request.LocationAddress{
			EndLocation: placeName,
		}
	}

	pd, _ := json.Marshal(apiData)
	//log.Println("打印测试数据 - OrderCompleteApiData", string(pd))

	return string(pd)
}

// 生成平台订单
func (wxlogic *WxOrderLogic) CreateOrderByPayScore(param *request.CreateOrderReq, resultData *wechatpay.PayData, placeInfo *placemodel.PlaceModel) bool {
	//memInfo := memberdao.NewMemberDao().GetMemberInfoByOpenid(resultData.Get("openid")).Unwrap().(*membermodel.MembersModel)
	wc := NewSettingLogic().GetPaySettingByAppid(resultData.Get("appid"))
	memInfo := memberdao.NewMemberDao().GetMemberInfoByOpenidAndAppId(resultData.Get("openid"), wc.AppId).Unwrap().(*membermodel.MembersModel)
	devInfo := dao.NewDeviceDao().FetchDeviceInfoWithType(resultData.Get("attach")).Unwrap().(*devices.DeviceType)
	ployInfo := dao.NewPloysDao().GetPlacePloyInfo(devInfo.PlaceId, devInfo.SharedMode).Unwrap().(*ploys.PloyModel) // 获取商户最新奖励规则配置

	var uInfo *users.UserModel
	var isDraw, isTianhai int
	userInfo := dao.NewUserDao().GetUserInfoByPlaceId(devInfo.PlaceId).Unwrap().(*users.UserModel) // 获取用户详情
	uInfo = dao.GetParentUserInfoById(userInfo)
	// 会员不存在，则创建失败
	if memInfo.ID == 0 {
		return false
	}

	isDraw = NewNotifyLogic().PloyWxOrder(memInfo, ployInfo, placeInfo)

	if isDraw == 1 {
		if uInfo.ID == 0 { // 代理商被删除，不存在
			uInfo = dao.NewUserDao().GetUserInfoById(2).Unwrap().(*users.UserModel)
		} else {
			u := dao.GetLastDrawUserInfo(uInfo)                                  // 获取开启权益的代理商
			if u.ParentID == 0 && u.IsAdmin == 2 && placeInfo.BranchUserId > 0 { // 代理商都没开启
				uInfo = dao.NewUserDao().GetUserInfoById(placeInfo.BranchUserId).Unwrap().(*users.UserModel)
			} else {
				uInfo = u
			}
		}
	} else if isDraw == 2 {
		isDraw = 1
		isTianhai = 8
		uInfo = dao.NewUserDao().GetUserInfoById(2).Unwrap().(*users.UserModel)
	}
	log.Println("end-----------------------", isDraw, uInfo)

	//timeRange := &struct {
	//	StartTime string   `json:"start_time"`
	//	EndTime   string   `json:"end_time"`
	//}{}
	//_ = json.Unmarshal([]byte(resultData.Get("time_range")), timeRange)
	//stamp := wechatpay.ConvIntTime(timeRange.StartTime)
	money, _ := strconv.ParseInt(resultData.Get("total_amount"), 10, 64)

	// 1:等待下单 2:使用中 3:已撤销 4:交易失败 5:已完成 6:支付超时 7:待守约 10:已删除 11: 转入退款
	var status int8
	var stateDesc string
	switch resultData.Get("state") {
	case "CREATED":
		status = 1 // CREATED 商户已创建服务订单
		stateDesc = "商户已创建服务订单"
	case "DOING":
		status = 2 // DOING 服务订单进行中
		stateDesc = "服务订单进行中"
	case "DONE":
		status = 5 // DONE 服务订单完成
		stateDesc = "服务订单完成"
	case "REVOKED":
		status = 3 // REVOKED 商户取消服务订单
		stateDesc = "商户取消服务订单"
	case "EXPIRED":
		status = 4 // EXPIRED 服务订单已失效
		stateDesc = "服务订单已失效"
	}

	//var productIdKey = utils.Join("productId-", resultData.Get("openid"), "-", resultData.Get("attach"))

	// 不存在  新增
	m := orders.New().Mutate(
		orders.WithAppid(resultData.Get("appid")),
		//orders.WithDeviceSn(resultData.Get("attach")),
		orders.WithDeviceSn(param.DeviceSn),
		orders.WithMchid(resultData.Get("mchid")),
		//orders.WithOpenid(resultData.Get("openid")),
		orders.WithOpenid(param.Openid),
		orders.WithOutTradeNo(resultData.Get("order_id")),  // 微信订单号
		orders.WithTradeNo(resultData.Get("out_order_no")), // 商户订单号
		//orders.WithTradeType(resultData.Get("trade_type")),                    // 订单支付类型 - 微信支付分支付
		orders.WithTradeType("PreAuthPay"), // 订单支付类型 - 微信支付分支付
		orders.WithMoney(money),
		orders.WithMoneyStr(decimal.NewFromInt(money).Div(decimal.NewFromInt(100)).StringFixed(2)),
		orders.WithTradeState(resultData.Get("state")), // 微信交易 状态
		orders.WithTradeStateDesc(stateDesc),           // 微信交易状态描述
		orders.WithTradeStateDoing(resultData.Get("state_description")),
		orders.WithCreateAt(dingo.Time(time.Now().Unix())),
		orders.WithBeginAt(dingo.Time(time.Now().Unix())),
		orders.WithState(status),
		orders.WithOrderFrom("weixin"),
		orders.WithPayFrom(1), // 1免押 2押金
		orders.WithMemberId(memInfo.UUID),
		orders.WithMemberName(memInfo.NickName),
		orders.WithMemberPhone(memInfo.Phone),
		orders.WithPlaceId(devInfo.PlaceId),
		orders.WithPlaceName(devInfo.PlaceName),
		orders.WithSharedMode(devInfo.SharedMode),
		orders.WithPayMoney(money),
		orders.WithPayMoneyStr(decimal.NewFromInt(money).Div(decimal.NewFromInt(100)).StringFixed(2)),
		orders.WithTitle(devInfo.DeviceName),
		orders.WithFeeMode(int8(devInfo.FeeMode)),
		orders.WithPayType(3),
		//orders.WithProductId(global.Rdb.Get(context.Background(), productIdKey).Val()),
		orders.WithProductId(param.ProductId),
		orders.WithIsDraw(int8(isDraw)),       // 1抽单 0不抽单
		orders.WithIsTianHai(int8(isTianhai)), // 0新系统  1天海
		orders.WithUserId(userInfo.ID),
		orders.WithUserName(userInfo.Name),
		orders.WithParentId(userInfo.ParentID),
		orders.WithAgentUserId(uInfo.ID),
		orders.WithSettlementWay(1), // 未结算
		orders.WithProdType(devInfo.ProdType), // 设备类型  1  2  3
	)
	b := dao.NewOrderDao().InsertOrder(m).Unwrap().(bool)
	return b
	//insertOrderOk := dao.NewOrderDao().InsertOrder(m).Unwrap().(bool)
	//if insertOrderOk {
	//	// 订单插入成功 todo 更新设备信息、记录订单状态
	//	dm := devices.New().Mutate(
	//		devices.WithUpdateAt(dingo.Time(time.Now().Unix())),
	//		devices.WithStatus(3),
	//		devices.WithDeviceSn(resultData.Get("attach")),
	//	)
	//	dao.NewDeviceDao().UpdateDeviceBySn(dm).Unwrap()
	//}
}
